//===-- M68kInstrInfo.td - Main M68k Instruction Definition -*- tablegen -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file describes the M68k instruction set, defining the instructions
/// and properties of the instructions which are needed for code generation,
/// machine code emission, and analysis.
///
//===----------------------------------------------------------------------===//

include "M68kInstrFormats.td"

//===----------------------------------------------------------------------===//
// Profiles
//===----------------------------------------------------------------------===//

def MxSDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
def MxSDT_CallSeqEnd   : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;

def MxSDT_Call    : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;

def MxSDT_Ret     : SDTypeProfile<0, -1, [
  /* ADJ */ SDTCisVT<0, i32>
]>;

def MxSDT_TCRet   : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>;

def MxSDT_Wrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>;

def MxSDT_UnArithCCROut : SDTypeProfile<2, 1, [
  /* RES */ SDTCisInt<0>,
  /* CCR */ SDTCisVT<1, i8>,
  /* OPD */ SDTCisSameAs<0, 2>
]>;

// RES, CCR <- op LHS, RHS
def MxSDT_BiArithCCROut : SDTypeProfile<2, 2, [
  /* RES */ SDTCisInt<0>,
  /* CCR */ SDTCisVT<1, i8>,
  /* LHS */ SDTCisSameAs<0, 2>,
  /* RHS */ SDTCisSameAs<0, 3>
]>;

// RES, CCR <- op LHS, RHS, CCR
def MxSDT_BiArithCCRInOut : SDTypeProfile<2, 3, [
  /* RES 1 */ SDTCisInt<0>,
  /*   CCR */ SDTCisVT<1, i8>,
  /*   LHS */ SDTCisSameAs<0, 2>,
  /*   RHS */ SDTCisSameAs<0, 3>,
  /*   CCR */ SDTCisSameAs<1, 4>
]>;

// RES1, RES2, CCR <- op LHS, RHS
def MxSDT_2BiArithCCROut : SDTypeProfile<3, 2, [
  /* RES 1 */ SDTCisInt<0>,
  /* RES 2 */ SDTCisSameAs<0, 1>,
  /*   CCR */ SDTCisVT<1, i8>,
  /*   LHS */ SDTCisSameAs<0, 2>,
  /*   RHS */ SDTCisSameAs<0, 3>
]>;

def MxSDT_CmpTest : SDTypeProfile<1, 2, [
   /* CCR */ SDTCisVT<0, i8>,
   /* Ops */ SDTCisSameAs<1, 2>
]>;

def MxSDT_Cmov : SDTypeProfile<1, 4, [
  /*  ARG */ SDTCisSameAs<0, 1>,
  /*  ARG */ SDTCisSameAs<1, 2>,
  /* Cond */ SDTCisVT<3, i8>,
  /*  CCR */ SDTCisVT<4, i8>
]>;

def MxSDT_BrCond : SDTypeProfile<0, 3, [
  /* Dest */ SDTCisVT<0, OtherVT>,
  /* Cond */ SDTCisVT<1, i8>,
  /*  CCR */ SDTCisVT<2, i8>
]>;

def MxSDT_SetCC : SDTypeProfile<1, 2, [
  /* BOOL */ SDTCisVT<0, i8>,
  /* Cond */ SDTCisVT<1, i8>,
  /*  CCR */ SDTCisVT<2, i8>
]>;

def MxSDT_SetCC_C : SDTypeProfile<1, 2, [
  /* BOOL */ SDTCisInt<0>,
  /* Cond */ SDTCisVT<1, i8>,
  /*  CCR */ SDTCisVT<2, i8>
]>;


def MxSDT_SEG_ALLOCA : SDTypeProfile<1, 1,[
  /*  MEM */ SDTCisVT<0, iPTR>,
  /* SIZE */ SDTCisVT<1, iPTR>
]>;


//===----------------------------------------------------------------------===//
// Nodes
//===----------------------------------------------------------------------===//

def MxCallSeqStart : SDNode<"ISD::CALLSEQ_START", MxSDT_CallSeqStart,
                            [SDNPHasChain, SDNPOutGlue]>;

def MxCallSeqEnd   : SDNode<"ISD::CALLSEQ_END", MxSDT_CallSeqEnd,
                            [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;

def MxCall         : SDNode<"M68kISD::CALL", MxSDT_Call,
                            [SDNPHasChain, SDNPOutGlue,
                             SDNPOptInGlue, SDNPVariadic]>;

def MxRet   : SDNode<"M68kISD::RET", MxSDT_Ret,
                     [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;

def MxTCRet : SDNode<"M68kISD::TC_RETURN", MxSDT_TCRet,
                     [SDNPHasChain,  SDNPOptInGlue, SDNPVariadic]>;

def MxWrapper   : SDNode<"M68kISD::Wrapper",   MxSDT_Wrapper>;
def MxWrapperPC : SDNode<"M68kISD::WrapperPC", MxSDT_Wrapper>;

def MxAdd  : SDNode<"M68kISD::ADD",  MxSDT_BiArithCCROut, [SDNPCommutative]>;
def MxSub  : SDNode<"M68kISD::SUB",  MxSDT_BiArithCCROut>;
def MxOr   : SDNode<"M68kISD::OR",   MxSDT_BiArithCCROut, [SDNPCommutative]>;
def MxXor  : SDNode<"M68kISD::XOR",  MxSDT_BiArithCCROut, [SDNPCommutative]>;
def MxAnd  : SDNode<"M68kISD::AND",  MxSDT_BiArithCCROut, [SDNPCommutative]>;

def MxAddX : SDNode<"M68kISD::ADDX", MxSDT_BiArithCCRInOut>;
def MxSubX : SDNode<"M68kISD::SUBX", MxSDT_BiArithCCRInOut>;

def MxSMul : SDNode<"M68kISD::SMUL", MxSDT_BiArithCCROut, [SDNPCommutative]>;
def MxUMul : SDNode<"M68kISD::UMUL", MxSDT_2BiArithCCROut, [SDNPCommutative]>;

def MxCmp     : SDNode<"M68kISD::CMP", MxSDT_CmpTest>;
def MxBtst    : SDNode<"M68kISD::BTST", MxSDT_CmpTest>;

def MxCmov    : SDNode<"M68kISD::CMOV",        MxSDT_Cmov>;
def MxBrCond  : SDNode<"M68kISD::BRCOND",      MxSDT_BrCond, [SDNPHasChain]>;
def MxSetCC   : SDNode<"M68kISD::SETCC",       MxSDT_SetCC>;
def MxSetCC_C : SDNode<"M68kISD::SETCC_CARRY", MxSDT_SetCC_C>;


def MxSegAlloca : SDNode<"M68kISD::SEG_ALLOCA", MxSDT_SEG_ALLOCA,
                         [SDNPHasChain]>;


//===----------------------------------------------------------------------===//
// Operands
//===----------------------------------------------------------------------===//

/// Size is the size of the data, either bits of a register or number of bits
/// addressed in memory. Size id is a letter that identifies size.
class MxSize<int num, string id, string full> {
  int Num = num;
  string Id = id;
  string Full = full;
}

def MxSize8  : MxSize<8,  "b", "byte">;
def MxSize16 : MxSize<16, "w", "word">;
def MxSize32 : MxSize<32, "l", "long">;

class MxOpClass<string name,
                list<AsmOperandClass> superClasses = []> : AsmOperandClass {
  let Name = name;
  let ParserMethod = "parseMemOp";
  let SuperClasses = superClasses;
}

def MxRegClass : MxOpClass<"Reg">;
// Splitting asm register class to avoid ambiguous on operands'
// MatchClassKind. For instance, without this separation,
// both ADD32dd and ADD32dr has {MCK_RegClass, MCK_RegClass} for
// their operands, which makes AsmParser unable to pick the correct
// one in a deterministic way.
let RenderMethod = "addRegOperands", SuperClasses = [MxRegClass]in {
  def MxARegClass : MxOpClass<"AReg">;
  def MxDRegClass : MxOpClass<"DReg">;
}

class MxOperand<ValueType vt, MxSize size, string letter, RegisterClass rc, dag pat = (null_frag)> {
  ValueType VT = vt;
  string Letter = letter;
  MxSize Size = size;
  RegisterClass RC = rc;
  dag Pat = pat;
}

class MxRegOp<ValueType vt,
              RegisterClass rc,
              MxSize size,
              string letter,
              string pm = "printOperand">
    : RegisterOperand<rc, pm>,
      MxOperand<vt, size, letter, rc> {
  let ParserMatchClass = MxRegClass;
}

// REGISTER DIRECT. The operand is in the data register specified by
// the effective address register field.
def MxXRD16 : MxRegOp<i16, XR16, MxSize16, "r">;
def MxXRD32 : MxRegOp<i32, XR32, MxSize32, "r">;

def MxXRD16_TC : MxRegOp<i16, XR16_TC, MxSize16, "r">;
def MxXRD32_TC : MxRegOp<i32, XR32_TC, MxSize32, "r">;

// DATA REGISTER DIRECT. The operand is in the data register specified by
// the effective address register field.
let ParserMatchClass = MxDRegClass in {
  def MxDRD8  : MxRegOp<i8,  DR8,  MxSize8,  "d">;
  def MxDRD16 : MxRegOp<i16, DR16, MxSize16, "d">;
  def MxDRD32 : MxRegOp<i32, DR32, MxSize32, "d">;

  def MxDRD16_TC : MxRegOp<i16, DR16_TC, MxSize16, "d">;
  def MxDRD32_TC : MxRegOp<i32, DR32_TC, MxSize32, "d">;
}

// ADDRESS REGISTER DIRECT. The operand is in the address register specified by
// the effective address register field.
let ParserMatchClass = MxARegClass in {
  def MxARD16 : MxRegOp<i16, AR16, MxSize16, "a">;
  def MxARD32 : MxRegOp<i32, AR32, MxSize32, "a">;

  def MxARD16_TC : MxRegOp<i16, AR16_TC, MxSize16, "a">;
  def MxARD32_TC : MxRegOp<i32, AR32_TC, MxSize32, "a">;
}

class MxMemOp<dag ops, MxSize size, string letter,
              string printMethod = "printOperand",
              AsmOperandClass parserMatchClass = ImmAsmOperand>
    : Operand<iPTR>, MxOperand<iPTR, size, letter, ?> {
  let PrintMethod = printMethod;
  let MIOperandInfo = ops;
  let ParserMatchClass = parserMatchClass;
  let OperandType = "OPERAND_MEMORY";
}

// ADDRESS REGISTER INDIRECT. The address of the operand is in the address
// register specified by the register field. The reference is classified as
// a data reference with the exception of the jump and jump-to-subroutine
// instructions.
def MxARI         : MxOpClass<"ARI">;
def MxARI8        : MxMemOp<(ops AR32), MxSize8,  "j", "printARI8Mem", MxARI>;
def MxARI16       : MxMemOp<(ops AR32), MxSize16, "j", "printARI16Mem", MxARI>;
def MxARI32       : MxMemOp<(ops AR32), MxSize32, "j", "printARI32Mem", MxARI>;

def MxARI8_TC     : MxMemOp<(ops AR32_TC), MxSize8,  "j", "printARI8Mem", MxARI>;
def MxARI16_TC    : MxMemOp<(ops AR32_TC), MxSize16, "j", "printARI16Mem", MxARI>;
def MxARI32_TC    : MxMemOp<(ops AR32_TC), MxSize32, "j", "printARI32Mem", MxARI>;

// ADDRESS REGISTER INDIRECT WITH POSTINCREMENT. The address of the operand is
// in the address register specified by the register field. After the operand
// address is used, it is incremented by one, two, or four depending upon whether
// the size of the operand is byte, word, or long word. If the address register
// is the stack pointer and the operand size is byte, the address is incremented
// by two rather than one to keep the stack pointer on a word boundary.
// The reference is classified as a data reference.
def MxARIPI       : MxOpClass<"ARIPI">;
def MxARIPI8      : MxMemOp<(ops AR32), MxSize8,  "o", "printARIPI8Mem", MxARIPI>;
def MxARIPI16     : MxMemOp<(ops AR32), MxSize16, "o", "printARIPI16Mem", MxARIPI>;
def MxARIPI32     : MxMemOp<(ops AR32), MxSize32, "o", "printARIPI32Mem", MxARIPI>;

def MxARIPI8_TC   : MxMemOp<(ops AR32_TC), MxSize8,  "o", "printARIPI8Mem", MxARIPI>;
def MxARIPI16_TC  : MxMemOp<(ops AR32_TC), MxSize16, "o", "printARIPI16Mem", MxARIPI>;
def MxARIPI32_TC  : MxMemOp<(ops AR32_TC), MxSize32, "o", "printARIPI32Mem", MxARIPI>;

// ADDRESS REGISTER INDIRECT WITH PREDECREMENT. The address of the operand is in
// the address register specified by the register field. Before the operand
// address is used, it is decremented by one, two, or four depending upon whether
// the operand size is byte, word, or long word. If the address register is
// the stack pointer and the operand size is byte, the address is decremented by
// two rather than one to keep the stack pointer on a word boundary.
// The reference is classified as a data reference.
def MxARIPD       : MxOpClass<"ARIPD">;
def MxARIPD8      : MxMemOp<(ops AR32), MxSize8,  "e", "printARIPD8Mem", MxARIPD>;
def MxARIPD16     : MxMemOp<(ops AR32), MxSize16, "e", "printARIPD16Mem", MxARIPD>;
def MxARIPD32     : MxMemOp<(ops AR32), MxSize32, "e", "printARIPD32Mem", MxARIPD>;

def MxARIPD8_TC   : MxMemOp<(ops AR32_TC), MxSize8,  "e", "printARIPD8Mem", MxARIPD>;
def MxARIPD16_TC  : MxMemOp<(ops AR32_TC), MxSize16, "e", "printARIPD16Mem", MxARIPD>;
def MxARIPD32_TC  : MxMemOp<(ops AR32_TC), MxSize32, "e", "printARIPD32Mem", MxARIPD>;

// ADDRESS REGISTER INDIRECT WITH DISPLACEMENT. This addressing mode requires one
// word of extension. The address of the operand is the sum of the address in
// the address register and the sign-extended 16-bit displacement integer in the
// extension word. The reference is classified as a data reference with the
// exception of the jump and jump-to-subroutine instructions.
def MxARID        : MxOpClass<"ARID">;
def MxARID8       : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize8,  "p", "printARID8Mem", MxARID>;
def MxARID16      : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize16, "p", "printARID16Mem", MxARID>;
def MxARID32      : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize32, "p", "printARID32Mem", MxARID>;

def MxARID8_TC    : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize8,  "p", "printARID8Mem", MxARID>;
def MxARID16_TC   : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize16, "p", "printARID16Mem", MxARID>;
def MxARID32_TC   : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize32, "p", "printARID32Mem", MxARID>;

// ADDRESS REGISTER INDIRECT WITH INDEX. This addressing mode requires one word
// of extension. The address of the operand is the sum of the address in the
// address register, the signextended displacement integer in the low order eight
// bits of the extension word, and the contents of the index register.
// The reference is classified as a data reference with the exception of the
// jump and jump-to-subroutine instructions
def MxARII       : MxOpClass<"ARII">;
def MxARII8      : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index),
                           MxSize8,  "f", "printARII8Mem", MxARII>;
def MxARII16     : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index),
                           MxSize16, "f", "printARII16Mem", MxARII>;
def MxARII32     : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index),
                           MxSize32, "f", "printARII32Mem", MxARII>;

def MxARII8_TC   : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index),
                           MxSize8,  "f", "printARII8Mem", MxARII>;
def MxARII16_TC  : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index),
                           MxSize16, "f", "printARII16Mem", MxARII>;
def MxARII32_TC  : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index),
                           MxSize32, "f", "printARII32Mem", MxARII>;

// ABSOLUTE SHORT ADDRESS. This addressing mode requires one word of extension.
// The address of the operand is the extension word. The 16-bit address is sign
// extended before it is used.  The reference is classified as a data reference
// with the exception of the jump and jump-tosubroutine instructions.
def MxAddr     : MxOpClass<"Addr">;
let RenderMethod = "addAddrOperands" in {
  // This hierarchy ensures Addr8 will always be parsed
  // before other larger-width variants.
  def MxAddr32   : MxOpClass<"Addr32", [MxAddr]>;
  def MxAddr16   : MxOpClass<"Addr16", [MxAddr32]>;
  def MxAddr8    : MxOpClass<"Addr8",  [MxAddr16]>;
}

def MxAS8      : MxMemOp<(ops OtherVT), MxSize8,  "B", "printAS8Mem",  MxAddr8>;
def MxAS16     : MxMemOp<(ops OtherVT), MxSize16, "B", "printAS16Mem", MxAddr16>;
def MxAS32     : MxMemOp<(ops OtherVT), MxSize32, "B", "printAS32Mem", MxAddr32>;

// ABSOLUTE LONG ADDRESS. This addressing mode requires two words of extension.
// The address of the operand is developed by the concatenation of the extension
// words. The high order part of the address is the first extension word; the low
// order part of the address is the second extension word. The reference is
// classified as a data reference with the exception of the jump and jump
// to-subroutine instructions.
def MxAL8      : MxMemOp<(ops OtherVT), MxSize8,  "b", "printAL8Mem",  MxAddr8>;
def MxAL16     : MxMemOp<(ops OtherVT), MxSize16, "b", "printAL16Mem", MxAddr16>;
def MxAL32     : MxMemOp<(ops OtherVT), MxSize32, "b", "printAL32Mem", MxAddr32>;

def MxPCD : MxOpClass<"PCD">;
def MxPCI : MxOpClass<"PCI">;

let OperandType = "OPERAND_PCREL" in {
// PROGRAM COUNTER WITH DISPLACEMENT. This addressing mode requires one word of
// extension. The address of the operand is the sum of the address in the program
// counter and the Sign-extended 16-bit displacement integer in the extension
// word. The value in the program counter is the address of the extension word.
// The reference is classified as a program reference.
def MxPCD8     : MxMemOp<(ops i16imm), MxSize8,  "q", "printPCD8Mem", MxPCD>;
def MxPCD16    : MxMemOp<(ops i16imm), MxSize16, "q", "printPCD16Mem", MxPCD>;
def MxPCD32    : MxMemOp<(ops i16imm), MxSize32, "q", "printPCD32Mem", MxPCD>;

// PROGRAM COUNTER WITH INDEX. This addressing mode requires one word of
// extension. The address is the sum of the address in the program counter, the
// sign-extended displacement integer in the lower eight bits of the extension
// word, and the contents of the index register.  The value in the program
// counter is the address of the extension word. This reference is classified as
// a program reference.
def MxPCI8   : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize8,  "k", "printPCI8Mem", MxPCI>;
def MxPCI16  : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize16, "k", "printPCI16Mem", MxPCI>;
def MxPCI32  : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize32, "k", "printPCI32Mem", MxPCI>;
} // OPERAND_PCREL

def MxImm : AsmOperandClass {
  let Name = "MxImm";
  let PredicateMethod = "isImm";
  let RenderMethod = "addImmOperands";
  let ParserMethod = "parseImm";
}

class MxOp<ValueType vt, MxSize size, string letter>
    : Operand<vt>,
      MxOperand<vt, size, letter, ?> {
  let ParserMatchClass = MxImm;
}

let OperandType = "OPERAND_IMMEDIATE",
    PrintMethod = "printImmediate" in {
// IMMEDIATE DATA. This addressing mode requires either one or two words of
// extension depending on the size of the operation.
//     Byte Operation - operand is low order byte of extension word
//     Word Operation - operand is extension word
//     Long Word Operation - operand is in the two extension words,
//                           high order 16 bits are in the first
//                           extension word, low order 16 bits are
//                           in the second extension word.
def Mxi8imm  : MxOp<i8,  MxSize8,  "i">;
def Mxi16imm : MxOp<i16, MxSize16, "i">;
def Mxi32imm : MxOp<i32, MxSize32, "i">;
} // OPERAND_IMMEDIATE

class MxBrTargetOperand<int N> : Operand<OtherVT> {
  let OperandType = "OPERAND_PCREL";
  let PrintMethod = "printPCRelImm";
  let ParserMatchClass = !cast<AsmOperandClass>("MxAddr"#N);
}
// Branch targets have OtherVT type and print as pc-relative values.
def MxBrTarget8  : MxBrTargetOperand<8>;
def MxBrTarget16 : MxBrTargetOperand<16>;
def MxBrTarget32 : MxBrTargetOperand<32>;

// Used with MOVEM
def MxMoveMaskClass : MxOpClass<"MoveMask">;
def MxMoveMask : MxOp<i16, MxSize16, "m"> {
  let OperandType = "OPERAND_IMMEDIATE";
  let PrintMethod = "printMoveMask";
  let ParserMatchClass = MxMoveMaskClass;
}

//===----------------------------------------------------------------------===//
// Predicates
//===----------------------------------------------------------------------===//

def SmallCode    : Predicate<"TM.getCodeModel() == CodeModel::Small">;
def KernelCode   : Predicate<"TM.getCodeModel() == CodeModel::Kernel">;
def FarData      : Predicate<"TM.getCodeModel() != CodeModel::Small &&"
                             "TM.getCodeModel() != CodeModel::Kernel">;
def NearData     : Predicate<"TM.getCodeModel() == CodeModel::Small ||"
                             "TM.getCodeModel() == CodeModel::Kernel">;
def IsPIC        : Predicate<"TM.isPositionIndependent()">;
def IsNotPIC     : Predicate<"!TM.isPositionIndependent()">;

// ISA versions
foreach i = [0,1,2,4,6] in
def AtLeastM680 # i # "0" : Predicate<"Subtarget->atLeastM680"#i#"0()">,
                            AssemblerPredicate<(all_of
                                                !cast<SubtargetFeature>("FeatureISA"#i#"0"))>;

//===----------------------------------------------------------------------===//
// Condition Codes
//
// These MUST be kept in sync with codes enum in M68kInstrInfo.h
//===----------------------------------------------------------------------===//

def MxCONDt   : PatLeaf<(i8 0)>;  // True
def MxCONDf   : PatLeaf<(i8 1)>;  // False
def MxCONDhi  : PatLeaf<(i8 2)>;  // High
def MxCONDls  : PatLeaf<(i8 3)>;  // Less or Same
def MxCONDcc  : PatLeaf<(i8 4)>;  // Carry Clear
def MxCONDcs  : PatLeaf<(i8 5)>;  // Carry Set
def MxCONDne  : PatLeaf<(i8 6)>;  // Not Equal
def MxCONDeq  : PatLeaf<(i8 7)>;  // Equal
def MxCONDvc  : PatLeaf<(i8 8)>;  // Overflow Clear
def MxCONDvs  : PatLeaf<(i8 9)>;  // Overflow Set
def MxCONDpl  : PatLeaf<(i8 10)>; // Plus
def MxCONDmi  : PatLeaf<(i8 11)>; // Minus
def MxCONDge  : PatLeaf<(i8 12)>; // Greater or Equal
def MxCONDlt  : PatLeaf<(i8 13)>; // Less Than
def MxCONDgt  : PatLeaf<(i8 14)>; // Greater Than
def MxCONDle  : PatLeaf<(i8 15)>; // Less or Equal


//===----------------------------------------------------------------------===//
// Complex Patterns
//===----------------------------------------------------------------------===//

// NOTE Though this CP is not strictly necessarily it will simplify instruciton
// definitions
def MxCP_ARI   : ComplexPattern<iPTR, 1, "SelectARI",
                                [], [SDNPWantParent]>;

def MxCP_ARIPI : ComplexPattern<iPTR, 1, "SelectARIPI",
                                [], [SDNPWantParent]>;

def MxCP_ARIPD : ComplexPattern<iPTR, 1, "SelectARIPD",
                                [], [SDNPWantParent]>;

def MxCP_ARID  : ComplexPattern<iPTR, 2, "SelectARID",
                                [add, sub, mul, or, shl, frameindex],
                                [SDNPWantParent]>;

def MxCP_ARII  : ComplexPattern<iPTR, 3, "SelectARII",
                                [add, sub, mul, or, shl, frameindex],
                                [SDNPWantParent]>;

def MxCP_AL    : ComplexPattern<iPTR, 1, "SelectAL",
                                [add, sub, mul, or, shl],
                                [SDNPWantParent]>;

def MxCP_PCD   : ComplexPattern<iPTR, 1, "SelectPCD",
                                [add, sub, mul, or, shl],
                                [SDNPWantParent]>;

def MxCP_PCI   : ComplexPattern<iPTR, 2, "SelectPCI",
                                [add, sub, mul, or, shl], [SDNPWantParent]>;


//===----------------------------------------------------------------------===//
// Pattern Fragments
//===----------------------------------------------------------------------===//

def MximmSExt8  : PatLeaf<(i8  imm)>;
def MximmSExt16 : PatLeaf<(i16 imm)>;
def MximmSExt32 : PatLeaf<(i32 imm)>;

// Used for Shifts and Rotations, since M68k immediates in these instructions
// are 1 <= i <= 8. Generally, if immediate is bigger than 8 it will be moved
// to a register and then an operation is performed.
//
// TODO Need to evaluate whether splitting one big shift(or rotate)
// into a few smaller is faster than doing a move, if so do custom lowering
def Mximm8_1to8   : ImmLeaf<i8,  [{ return Imm >= 1 && Imm <= 8; }]>;
def Mximm16_1to8  : ImmLeaf<i16, [{ return Imm >= 1 && Imm <= 8; }]>;
def Mximm32_1to8  : ImmLeaf<i32, [{ return Imm >= 1 && Imm <= 8; }]>;

// Helper fragments for loads.
// It's always safe to treat a anyext i16 load as a i32 load if the i16 is
// known to be 32-bit aligned or better. Ditto for i8 to i16.
def Mxloadi16 : PatFrag<(ops node:$ptr), (i16 (unindexedload node:$ptr)), [{
  LoadSDNode *LD = cast<LoadSDNode>(N);
  ISD::LoadExtType ExtType = LD->getExtensionType();
  if (ExtType == ISD::NON_EXTLOAD)
    return true;
  if (ExtType == ISD::EXTLOAD)
    return LD->getAlign() >= 2 && !LD->isSimple();
  return false;
}]>;

def Mxloadi32 : PatFrag<(ops node:$ptr), (i32 (unindexedload node:$ptr)), [{
  LoadSDNode *LD = cast<LoadSDNode>(N);
  ISD::LoadExtType ExtType = LD->getExtensionType();
  if (ExtType == ISD::NON_EXTLOAD)
    return true;
  if (ExtType == ISD::EXTLOAD)
    return LD->getAlign() >= 4 && !LD->isSimple();
  return false;
}]>;

def Mxloadi8         : PatFrag<(ops node:$ptr), (i8  (load node:$ptr))>;

def MxSExtLoadi16i8  : PatFrag<(ops node:$ptr), (i16 (sextloadi8 node:$ptr))>;
def MxSExtLoadi32i8  : PatFrag<(ops node:$ptr), (i32 (sextloadi8 node:$ptr))>;
def MxSExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (sextloadi16 node:$ptr))>;

def MxZExtLoadi8i1   : PatFrag<(ops node:$ptr), (i8  (zextloadi1 node:$ptr))>;
def MxZExtLoadi16i1  : PatFrag<(ops node:$ptr), (i16 (zextloadi1 node:$ptr))>;
def MxZExtLoadi32i1  : PatFrag<(ops node:$ptr), (i32 (zextloadi1 node:$ptr))>;
def MxZExtLoadi16i8  : PatFrag<(ops node:$ptr), (i16 (zextloadi8 node:$ptr))>;
def MxZExtLoadi32i8  : PatFrag<(ops node:$ptr), (i32 (zextloadi8 node:$ptr))>;
def MxZExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (zextloadi16 node:$ptr))>;

def MxExtLoadi8i1    : PatFrag<(ops node:$ptr), (i8  (extloadi1 node:$ptr))>;
def MxExtLoadi16i1   : PatFrag<(ops node:$ptr), (i16 (extloadi1 node:$ptr))>;
def MxExtLoadi32i1   : PatFrag<(ops node:$ptr), (i32 (extloadi1 node:$ptr))>;
def MxExtLoadi16i8   : PatFrag<(ops node:$ptr), (i16 (extloadi8 node:$ptr))>;
def MxExtLoadi32i8   : PatFrag<(ops node:$ptr), (i32 (extloadi8 node:$ptr))>;
def MxExtLoadi32i16  : PatFrag<(ops node:$ptr), (i32 (extloadi16 node:$ptr))>;


//===----------------------------------------------------------------------===//
// Type Fixtures
//
// Type Fixtures are ValueType related information sets that usually go together
//===----------------------------------------------------------------------===//

// TODO make it folded like MxType8.F.Op nad MxType8.F.Pat
// TODO move strings into META subclass
// vt: Type of data this fixture refers to
// prefix: Prefix used to identify type
// postfix: Prefix used to qualify type
class MxType<ValueType vt, string prefix, string postfix,
             // rLet: Register letter
             // rOp:  Supported any register operand
             string rLet, MxOperand rOp,
             // jOp:  Supported ARI operand
             // jPat: What ARI pattern to use
             MxOperand jOp, ComplexPattern jPat,
             // oOp:  Supported ARIPI operand
             // oPat: What ARIPI pattern is used
             MxOperand oOp, ComplexPattern oPat,
             // eOp:  Supported ARIPD operand
             // ePat: What ARIPD pattern is used
             MxOperand eOp, ComplexPattern ePat,
             // pOp:  Supported ARID operand
             // pPat: What ARID pattern is used
             MxOperand pOp, ComplexPattern pPat,
             // fOp:  Supported ARII operand
             // fPat: What ARII pattern is used
             MxOperand fOp, ComplexPattern fPat,
             // bOp:  Supported absolute operand
             // bPat: What absolute pattern is used
             MxOperand bOp, ComplexPattern bPat,
             // qOp:  Supported PCD operand
             // qPat: What PCD pattern is used
             MxOperand qOp, ComplexPattern qPat,
             // kOp:  Supported PCI operand
             // kPat: What PCI pattern is used
             MxOperand kOp, ComplexPattern kPat,
             // iOp:  Supported immediate operand
             // iPat: What immediate pattern is used
             MxOperand iOp, PatFrag iPat,
             // load: What load operation is used with MEM
             PatFrag load> {
  int Size = vt.Size;
  ValueType VT = vt;
  string Prefix = prefix;
  string Postfix = postfix;

  string RLet = rLet;
  MxOperand ROp = rOp;

  MxOperand JOp = jOp;
  ComplexPattern JPat = jPat;

  MxOperand OOp = oOp;
  ComplexPattern OPat = oPat;

  MxOperand EOp = eOp;
  ComplexPattern EPat = ePat;

  MxOperand POp = pOp;
  ComplexPattern PPat = pPat;

  MxOperand FOp = fOp;
  ComplexPattern FPat = fPat;

  MxOperand BOp = bOp;
  ComplexPattern BPat = bPat;

  MxOperand QOp = qOp;
  ComplexPattern QPat = qPat;

  MxOperand KOp = kOp;
  ComplexPattern KPat = kPat;

  MxOperand IOp = iOp;
  PatFrag IPat = iPat;

  PatFrag Load = load;
}

// Provides an alternative way to access the MxOperand and
// patterns w.r.t a specific addressing mode.
class MxOpBundle<int size, MxOperand op, ComplexPattern pat> {
  int Size = size;
  MxOperand Op = op;
  ComplexPattern Pat = pat;
}

class MxImmOpBundle<int size, MxOperand op, PatFrag pat>
  : MxOpBundle<size, op, ?> {
  PatFrag ImmPat = pat;
}

// TODO: We can use MxOp<S>AddrMode_<AM> in more places to
// replace MxType-based operand factoring.
foreach size = [8, 16, 32] in {
  // Dn
  def MxOp#size#AddrMode_d
    : MxOpBundle<size, !cast<MxOperand>("MxDRD"#size), ?>;

  // (An)
  def MxOp#size#AddrMode_j
    : MxOpBundle<size, !cast<MxOperand>("MxARI"#size), MxCP_ARI>;

  // (An)+
  def MxOp#size#AddrMode_o
    : MxOpBundle<size, !cast<MxOperand>("MxARIPI"#size), MxCP_ARIPI>;

  // -(An)
  def MxOp#size#AddrMode_e
    : MxOpBundle<size, !cast<MxOperand>("MxARIPD"#size), MxCP_ARIPD>;

  // (i,An)
  def MxOp#size#AddrMode_p
    : MxOpBundle<size, !cast<MxOperand>("MxARID"#size), MxCP_ARID>;

  // (i,An,Xn)
  def MxOp#size#AddrMode_f
    : MxOpBundle<size, !cast<MxOperand>("MxARII"#size), MxCP_ARII>;

  // (ABS).L
  def MxOp#size#AddrMode_b
    : MxOpBundle<size, !cast<MxOperand>("MxAL"#size), MxCP_AL>;

  // (i,PC)
  def MxOp#size#AddrMode_q
    : MxOpBundle<size, !cast<MxOperand>("MxPCD"#size), MxCP_PCD>;

  // (i,PC,Xn)
  def MxOp#size#AddrMode_k
    : MxOpBundle<size, !cast<MxOperand>("MxPCI"#size), MxCP_PCI>;

  // #imm
  def MxOp#size#AddrMode_i
    : MxImmOpBundle<size, !cast<MxOperand>("Mxi"#size#"imm"),
                    !cast<PatFrag>("MximmSExt"#size)>;
} // foreach size = [8, 16, 32]

foreach size = [16, 32] in {
  // An
  def MxOp#size#AddrMode_a
    : MxOpBundle<size, !cast<MxOperand>("MxARD"#size), ?>;

  // Xn
  def MxOp#size#AddrMode_r
    : MxOpBundle<size, !cast<MxOperand>("MxXRD"#size), ?>;
} // foreach size = [16, 32]

class MxType8Class<string rLet, MxOperand reg>
    : MxType<i8, "b", "", rLet, reg,
             MxARI8,   MxCP_ARI,
             MxARIPI8, MxCP_ARIPI,
             MxARIPD8, MxCP_ARIPD,
             MxARID8,  MxCP_ARID,
             MxARII8,  MxCP_ARII,
             MxAL8,    MxCP_AL,
             MxPCD8,   MxCP_PCD,
             MxPCI8,   MxCP_PCI,
             Mxi8imm,  MximmSExt8,
             Mxloadi8>;

def MxType8 : MxType8Class<?,?>;

class MxType16Class<string rLet, MxOperand reg>
    : MxType<i16, "w", "", rLet, reg,
             MxARI16,   MxCP_ARI,
             MxARIPI16, MxCP_ARIPI,
             MxARIPD16, MxCP_ARIPD,
             MxARID16,  MxCP_ARID,
             MxARII16,  MxCP_ARII,
             MxAL16,    MxCP_AL,
             MxPCD16,   MxCP_PCD,
             MxPCI16,   MxCP_PCI,
             Mxi16imm,  MximmSExt16,
             Mxloadi16>;

def MxType16 : MxType16Class<?,?>;

class MxType32Class<string rLet, MxOperand reg>
    : MxType<i32, "l", "", rLet, reg,
             MxARI32,   MxCP_ARI,
             MxARIPI32, MxCP_ARIPI,
             MxARIPD32, MxCP_ARIPD,
             MxARID32,  MxCP_ARID,
             MxARII32,  MxCP_ARII,
             MxAL32,    MxCP_AL,
             MxPCD32,   MxCP_PCD,
             MxPCI32,   MxCP_PCI,
             Mxi32imm,  MximmSExt32,
             Mxloadi32>;

def MxType32 : MxType32Class<?,?>;


def MxType8d : MxType8Class<"d", MxDRD8>;

def MxType16d : MxType16Class<"d", MxDRD16>;
def MxType16a : MxType16Class<"a", MxARD16>;
def MxType16r : MxType16Class<"r", MxXRD16>;
def MxType32d : MxType32Class<"d", MxDRD32>;
def MxType32a : MxType32Class<"a", MxARD32>;
def MxType32r : MxType32Class<"r", MxXRD32>;

let Postfix = "_TC" in {
def MxType16d_TC : MxType16Class<"d", MxDRD16_TC>;
def MxType16a_TC : MxType16Class<"a", MxARD16_TC>;
def MxType16r_TC : MxType16Class<"r", MxXRD16_TC>;
def MxType32d_TC : MxType32Class<"d", MxDRD32_TC>;
def MxType32a_TC : MxType32Class<"a", MxARD32_TC>;
def MxType32r_TC : MxType32Class<"r", MxXRD32_TC>;
}


//===----------------------------------------------------------------------===//
// Subsystems
//===----------------------------------------------------------------------===//

include "M68kInstrData.td"
include "M68kInstrShiftRotate.td"
include "M68kInstrBits.td"
include "M68kInstrArithmetic.td"
include "M68kInstrControl.td"
include "M68kInstrAtomics.td"

include "M68kInstrCompiler.td"
